/*
 * Copyright 2010 Alexander Ulizko
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ulizko.template.soy.javaSrc;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.ulizko.template.soy.utils.FileUtils;
import com.google.common.base.Preconditions;
import org.gradle.api.file.FileCollection;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * Stock of the soy files.
 * Can convert provided list of paths to soy files or directories to the list of soy files.
 *
 * @author Alexander <alexander@ulizko.com> Ulizko
 */
public class SoyFileStock {
   /**
     * List of the soy input files. For each file should be generated blob java src mirror file with
     * same name but *.java extension.
     * (Warning: it should preserve directory structure in order to avoid filename conflicts)
     * Each entry should be path to the soy input file
     * or to directory contained on or more such files
     */
    private List<String> fileNames = new ArrayList<String>();

    /**
     * Adds file name to the input files list
     *
     * @param path A path to a file
     * @return Instance of {@link SoyFileStock} for chain method call support.
     */
    public SoyFileStock add(String path) {
        if (!fileNames.contains(path))
            fileNames.add(path);

        return this;
    }

    /**
     * Add multiple file paths
     *
     * @param paths Array of file paths
     * @return Instance of {@link SoyFileStock} for chain method call support.
     */
    public SoyFileStock add(String[] paths) {
        for (String path : paths) {
            add(path);
        }

        return this;
    }

    /**
     * Add multiple file paths
     *
     * @param paths List of file paths
     * @return Instance of {@link SoyFileStock} for chain method call support.
     */
    public SoyFileStock add(List<String> paths) {
        for (String path : paths) {
            add(path);
        }

        return this;
    }

    /**
     * Empty constructor, just create an instance of {@link SoyFileStock}.
     */
    public SoyFileStock() {}

    /**
     * Creates instance of SoyFileStock and stores provided array of soy file paths.
     * @param paths array of paths to soy files or to directories. 
     */
    public SoyFileStock(List<String> paths) {
        add(paths);
    }

    /**
     * Creates instance of SoyFileStock and stores provided path to soy file.
     * @param path Paths to soy file or to directory.
     */
    public SoyFileStock(String path) {
        add(path);
    }

    /**
     * Creates instance of SoyFileStock and stores provided files.
     * @param files Soy files collection.
     */
    public SoyFileStock(FileCollection files) {
        for (File file : files) {
            add(file.getPath());
        }
    }

    public void checkFiles() {
        List<String> result = new ArrayList<String>();
        // expand file names to qualified file names or (if a directory) convert it to file paths collection
        for (String path : fileNames) {
            File file = new File(path);
            Preconditions.checkNotNull(file);
            Preconditions.checkArgument(file.exists(), "%s doesn't exists", file.toString());

            // check if file is a directory
            if (file.isDirectory()) {
                // explore directory content to find every *.soy file
                result.addAll(FileUtils.retreiveSoyFilePathsFromDirectory(file));
            } else {
                // check if file has .soy extension
                Preconditions.checkArgument(FileUtils.isSoyFile(file), "%s should have soy extension", file.toString());
                result.add(file.toString());
            }
        }

        // check if there actually are at least one soy-file
        Preconditions.checkArgument(result.size() > 0, "You should provide at least one path to real soy input file. \n" +
                "Note: soy file must have .soy extension.");

        fileNames = result;
    }

    public List<String> getFileNames() {
        return fileNames;
    }

    /**
     * I've been forced to introduce such a stupid method because of strange error on gradle build:
     * "java.lang.NoSuchMethod com.google.common.collect.ImmutableList.copyOf(Ljava/util/Collection)Lcom/google/common/collect/ImmutableList".
     * As well as "com.google.common.collect.ImmutableList.copyOf([Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList"
     * Strange is that if I use this method, say, inside of build scripts (after proper import) it works fine.
     * @return ImmutableList of file names.
     */
    public ImmutableList<String> getFileNamesAsImmutableList() {
        return ImmutableList.copyOf(fileNames);
    }
}
